/**
    ******************************************************************************
    * 文件名称      : USART2_Config.c
    * 文件功能      : USART2串口通信模块
    * 适用平台      : STM32F10x系列（基于标准外设库）
    * 开发环境      : Keil MDK-ARM with STM32标准库
    * 注意事项      : 
    *   1. 使用前需在头文件配置时钟频率
    *   2. 需启用USART2全局中断（NVIC配置）
    *   3. 浮点型printf需开启MicroLIB或重写相关函数
    ******************************************************************************
**/

#include "USART2_Config.h"

/* 私有宏定义 ----------------------------------------------------------------*/
#define USART2_RECV_BUF_SIZE  128  // 接收缓冲区大小（未使用但建议添加）

/**
    ******************************************************************************
    * 函数名称：USART2_Config
    * 功能描述：USART2初始化配置（全双工模式）
    * 输入参数：baud - 波特率（支持常用值2400-115200）
    * 硬件依赖：
    *   - PA9(TX): 复用推挽输出，50MHz速率
    *   - PA10(RX): 浮空输入，无上拉电阻
    * 寄存器操作：
    *   1. CR1[UE] = 1 使能USART
    *   2. CR1[RXNEIE] = 1 使能接收中断
    *   3. BRR寄存器自动计算波特率分频值
    * 配置流程：
    *   时钟使能→GPIO配置→USART参数设置→中断配置→模块使能
    ******************************************************************************
**/
void USART2_Config(u32 baud)
{
    USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    /* 时钟使能（APB2总线） */
    RCC_APB2PeriphClockCmd(RCC_APB1Periph_USART2 | RCC_APB2Periph_GPIOA, ENABLE);

    /* TX引脚配置（复用推挽输出） */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  // 复用推挽避免信号干扰
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 高速模式保证波形质量
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* RX引脚配置（浮空输入） */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 节省功耗
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* USART参数配置（8N1标准格式） */
    USART_InitStructure.USART_BaudRate = baud;       // 波特率误差<0.1%
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; 
    USART_InitStructure.USART_StopBits = USART_StopBits_1;     
    USART_InitStructure.USART_Parity = USART_Parity_No;       
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 
    USART_Init(USART2, &USART_InitStructure);         

    /* 中断配置（抢占优先级0，响应优先级0） */
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; // 最高优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* 使能接收中断（RXNE中断） */
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); 

    /* 使能USART（CR1[UE]位置1） */
    USART_Cmd(USART2, ENABLE);
}

/**
    ******************************************************************************
    * 函数名称：USART2_IRQHandler
    * 功能描述：USART2中断服务函数（CMSIS标准名称）
    * 中断触发条件：
    *   - 接收数据寄存器非空（RXNE）
    *   - 溢出错误（ORE）等未处理
    * 关键操作：
    *   1. 读取DR寄存器自动清除RXNE标志
    *   2. 使用USART2回传仅为示例，实际应统一接口
    * 优化建议：
    *   1. 添加接收缓冲区（环形队列）
    *   2. 处理帧错误/噪声标志
    ******************************************************************************
**/
void USART2_IRQHandler(void)
{
    /* RXNE中断处理（数据接收） */
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  
    {
        u8 data = USART_ReceiveData(USART2);  // 读取会清除RXNE标志
        USART_SendData(USART2, data);         // 示例：跨串口回传
        while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET); // 阻塞等待发送完成
    }
}

/**
    ******************************************************************************
    * 函数名称：USART2_SendByte
    * 功能描述：阻塞式单字节发送
    * 时序说明：
    *   1. 写入DR寄存器后硬件自动启动发送
    *   2. TXE标志在移位寄存器空时置位
    *   3. 最大阻塞时间 = 10bit/波特率（含起始/停止位）
    * 寄存器操作：
    *   - 写DR寄存器会清除TXE标志
    *   - 读取SR[TXE]状态
    ******************************************************************************
**/
void USART2_SendByte(u8 Byte)
{
    USART_SendData(USART2, Byte);  
    while(!USART_GetFlagStatus(USART2, USART_FLAG_TXE)); // 等待数据移出
}

/**
    ******************************************************************************
    * 函数名称：USART2_SendArray
    * 功能描述：二进制数组发送（支持任意数据）
    * 性能优化：
    *   - 使用指针递增代替数组索引
    *   - 长度递减减少比较运算
    * 安全机制：
    *   - const修饰防止意外修改源数据
    *   - 严格检查TXE标志避免覆盖
    ******************************************************************************
**/
void USART2_SendArray(const uint8_t *Array, uint16_t Length) 
{
    while (Length--) 
    {
        USART_SendData(USART2, *Array++);
        while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
    }
}

/**
    ******************************************************************************
    * 函数名称：USART_SendString
    * 功能描述：字符串发送（兼容标准C字符串）
    * 特殊处理：
    *   - 自动检测NULL终止符
    *   - 支持跨USART模块复用（通过USARTx参数）
    * 注意事项：
    *   - 不处理字符串溢出（需确保缓冲区有效）
    ******************************************************************************
**/
//void USART_SendString(USART_TypeDef* USARTx, const char *str) {
//    while (*str) {
//        USART_SendData(USARTx, *str++);
//        while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
//    }
//}

/**
    ******************************************************************************
    * 函数名称：USART2_Pow
    * 功能描述：整数幂运算（优化数字分解）
    * 算法说明：
    *   - 采用累乘法（时间复杂度O(n)）
    *   - 适用于小指数运算（y<10）
    * 改进建议：
    *   - 大指数运算可改用快速幂算法
    ******************************************************************************
**/
u32 USART2_Pow(u32 x, u32 y)
{
    uint32_t Result = 1;
    while(y--)
    {
        Result *= x;  
    }
    return Result;
}

/**
    ******************************************************************************
    * 函数名称：USART2_SendNumber
    * 功能描述：定长数字发送（自动补零）
    * 数字分解原理：
    *   1. 通过除数提取指定位的数字
    *   2. ASCII转换：数字+'0' = 对应字符
    * 示例说明：
    *   - USART2_SendNumber(123,5) → "00123"
    *   - 除数变化：10000→1000→100→10→1
    ******************************************************************************
**/
void USART2_SendNumber(uint32_t Num, uint8_t Length) 
{
    uint32_t divisor = 1;
    
    /* 预计算除数（避免重复幂运算） */
    for (uint8_t i = 1; i < Length; i++) 
    {
        divisor *= 10;
    }

    /* 高位到低位依次发送 */
    while (Length--) 
    {
        USART_SendData(USART2, (Num / divisor % 10) + '0');
        while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
        divisor /= 10;
    }
}

/**
    ******************************************************************************
    * 函数名称：fputc1
    * 功能描述：printf重定向（MicroLIB专用）
    * 底层依赖：
    *   - 依赖__use_no_semihosting_swi宏定义
    *   - 需在Options→Target中勾选"Use MicroLIB"
    * 工作机制：
    *   - printf内部会调用此函数输出字符
    ******************************************************************************
**/
int fputc2(int ch, FILE *f)
{
    USART2_SendByte(ch);  
    return ch;
}

/**
    ******************************************************************************
    * 函数名称：USART2_Printf
    * 功能描述：安全版格式化输出（独立实现）
    * 格式化支持：
    *   - 通过vsnprintf支持全部标准格式符
    *   - 缓冲区溢出保护（sizeof检测）
    * 资源消耗：
    *   - 栈空间占用：128字节缓冲区
    *   - 建议仅在调试时使用
    ******************************************************************************
**/
void USART2_Printf(const char *format, ...) 
{
    char String[128];                
    va_list arg;
    
    va_start(arg, format);
    vsnprintf(String, sizeof(String), format, arg); 
    va_end(arg);
    
    const char *p = String;
    while (*p) 
    {
        USART_SendData(USART2, *p++);
        while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
    }
}

